<template>
  <a-layout class="h-full">
    <a-layout-header class="tool">
      <a-space align="center">
        <template #split>
          <a-divider layout="vertical" />
        </template>
        <a-tooltip trigger="hover" :content="`${collapsed ? '展开' : '收起'}侧边栏`">
          <a-button size="mini" @click="onCollapse">
            <IconCaretRight v-if="collapsed" />
            <IconCaretLeft v-else />
          </a-button>
        </a-tooltip>
        <a-tooltip trigger="hover" content="撤销">
          <a-button :disabled="!canUndo" size="mini" class="bi-arrow-left" @click="undo()">
            <template #icon>
              <icon-arrow-left />
            </template>
          </a-button>
        </a-tooltip>
        <a-tooltip trigger="hover" content="前进">
          <a-button :disabled="!canRedo" size="mini" class="bi-arrow-right" @click="redo()">
            <template #icon>
              <icon-arrow-right />
            </template>
          </a-button>
        </a-tooltip>
      </a-space>
      <a-space>
        <a-popover
          v-for="item in plugins"
          :key="item.group"
          showArrow
          placement="bottom"
          trigger="click"
          :content-style="{ width: '500px' }"
        >
          <a-button size="mini"><i class="pr5" :class="item.icon" /> {{ item.group }}</a-button>
          <template #content>
            <div class="relative" style="height: 300px">
              <div class="flex flex-wrap gap-0" style="width: 270px">
                <div
                  v-for="component in item.children"
                  :key="component.name"
                  class="tool-component"
                  :draggable="true"
                  @dragstart="handleDragStart(component)"
                  :data-component="JSON.stringify(component)"
                  @click="addComponent(component)"
                  @mouseover="mouseOver(component)"
                  @mouseleave="componentInfo = {}"
                >
                  <a-image :src="component.icon" :preview="false" fit="contain" width="100%" height="50" />
                  <div>{{ component.title }}</div>
                </div>
              </div>
              <div style="width: 190px; border-radius: 10px" class="pb-5 absolute right-0 top-0">
                <template v-if="componentInfo.title">
                  <a-space direction="vertical" style="height: 500px" class="p10 overflow-y-auto">
                    <div class="text-xl">{{ componentInfo.title }}</div>
                    <div class="text-xs">{{ componentInfo.desc }}</div>
                    <template v-for="(setting, key) in componentInfo.dataConfigOption" :key="key">
                      <a-tag theme="primary" size="small">{{ setting.name }}</a-tag>
                      最大：{{ setting.max }} 个
                      {{ setting.name }}
                    </template>
                  </a-space>
                </template>
                <template v-else>
                  <h2>添加图表到画布</h2>
                  <div class="text-xs">
                    <div>1. 单击添加图表至选中组件下方</div>
                    <div>2. 或拖动至指定位置。</div>
                  </div>
                </template>
              </div>
            </div>
          </template>
        </a-popover>
      </a-space>
      <a-space size="1px">
        <a-tooltip trigger="hover" placement="bottom" content="格式刷">
          <a-button size="mini" @click="formatBrush"><span class="bi-magic-line" /></a-button>
        </a-tooltip>
        <a-divider layout="vertical" />
        <a-button size="mini" @click="scale = +scale - 0.1"> -</a-button>
        <a-dropdown placement="bottom" trigger="click" size="small" :options="scaleOptions">
          <a-button size="mini"> {{ (scale * 100).toFixed(0) }}%</a-button>
          <template #content>
            <a-doption v-for="item in scaleOptions" :key="item.value" @click="handleScaleSelect(item)">
              {{ item.content }}
            </a-doption>
          </template>
        </a-dropdown>
        <a-button size="mini" @click="scale = +scale + 0.1"> +</a-button>
        <a-divider layout="vertical" />
        <a-tooltip trigger="hover" placement="bottom" content="自适应">
          <a-button size="mini" @click="handleScale">
            <template #icon>
              <span class="bi-aspect-ratio-line" />
            </template>
          </a-button>
        </a-tooltip>
      </a-space>
    </a-layout-header>
    <a-layout-content class="canvas">
      <div class="canvas-container" ref="editor">
        <div
          id="container"
          ref="container"
          class="container shadow-2xl"
          :style="canvasEditStyle"
          @contextmenu.self="canvasClick"
          @dragover="handleDragOver"
          @drop="handleDragEnd"
        >
          <template v-for="item in componentList" :key="item.key">
            <prview-component :item="item" />
          </template>
        </div>
      </div>
    </a-layout-content>
  </a-layout>
</template>

<script setup>
import Moveable from "moveable"
import Selecto from "selecto"
import plugins from "@/plugins/list"
// import Guides from 'vue3-guides'
import {
  useVisual,
  useComponent,
  useScale,
  useMenus,
  setMoveableRef,
  useBrush,
  onCollapse,
  collapsed
} from "@/hooks/userEditor"
const { setMoveableReff } = setMoveableRef()
// import useDark from '@/hooks/useDark'
// const { isDark } = useDark
const { canvasEditStyle, commonStyle } = useVisual()
const { canvasClick } = useMenus()

const { componentList, addComponent, selectComponent, clearComponent, currentComponent, recordHistory, groupManager } =
  useComponent()
const editor = ref(null)
const { scale, scaleOptions, handleScaleSelect, handleScale } = useScale(editor)
const { undo, redo, canUndo, canRedo, commit } = recordHistory
let moveableRef = null
let targets = []

onMounted(() => {
  const container = document.getElementById("container")
  moveableRef = new Moveable(container, {
    target: targets,
    draggable: true,
    resizable: true,
    snappable: true,
    warpable: false,
    keepRatio: false,
    rotatable: true,
    origin: false,
    useResizeObserver: true,
    snapDirections: {
      top: true,
      left: true,
      bottom: true,
      right: true,
      center: true,
      middle: true
    },
    elementSnapDirections: {
      top: true,
      left: true,
      bottom: true,
      right: true,
      center: true,
      middle: true
    },
    verticalGuidelines: [0, commonStyle.value.width / 2, commonStyle.value.width],
    horizontalGuidelines: [0, commonStyle.value.height / 2, commonStyle.value.height],
    elementGuidelines: [],
    snapDistFormat: (distance) => `${distance}px`
  })
  setMoveableReff(moveableRef)
  const selecto = new Selecto({
    dragContainer: ".canvas",
    selectableTargets: [".component"],
    hitRate: 0,
    selectByClick: true,
    selectFromInside: true,
    toggleContinueSelect: ["shift"],
    ratio: 0
  })
  moveableRef.on("render", (e) => {
    e.target.style.cssText += e.cssText
    addStyle(true)
  })
  moveableRef.on("renderGroup", (e) => {
    e.events.forEach((ev) => {
      ev.target.style.cssText += ev.cssText
    })
  })
  moveableRef.on("renderEnd", (e) => {
    e.target.style.cssText += e.cssText
    addStyle(false)
  })
  moveableRef.on("dragEnd", (e) => {
    const translate = e?.lastEvent?.translate
    if (!translate) return
    currentComponent.value.element.left = parseInt(translate[0], 10)
    currentComponent.value.element.top = parseInt(translate[1], 10)
    commit()
  })
  moveableRef.on("resizeEnd", (e) => {
    const { width, height, drag } = e.lastEvent
    const { translate } = drag
    currentComponent.value.element.width = parseInt(width, 10)
    currentComponent.value.element.height = parseInt(height, 10)
    currentComponent.value.element.left = parseInt(translate[0], 10)
    currentComponent.value.element.top = parseInt(translate[1], 10)
    commit()
  })
  moveableRef.on("rotateEnd", (e) => {
    const { drag } = e.lastEvent
    const { translate } = drag
    currentComponent.value.element.left = parseInt(translate[0], 10)
    currentComponent.value.element.top = parseInt(translate[1], 10)
    currentComponent.value.element.rotate = parseInt(e.lastEvent.rotate, 10)
    addStyle(false)
    commit()
  })
  moveableRef.on("dragGroupEnd", (e) => {
    if (!e.lastEvent) return
    e.events.forEach((ev) => {
      ev.target.style.cssText += ev.cssText
      componentList.value.forEach((item) => {
        if (item.key === ev.target.dataset.key) {
          item.element.left = parseInt(ev.lastEvent.beforeTranslate[0], 10)
          item.element.top = parseInt(ev.lastEvent.beforeTranslate[1], 10)
        }
      })
    })
    commit()
  })
  moveableRef.on("resizeGroupEnd", (e) => {
    e.events.forEach((ev) => {
      const { width, height, drag } = ev.lastEvent
      const { translate } = drag
      ev.target.style.cssText += ev.cssText
      componentList.value.forEach((item) => {
        if (item.key === ev.target.dataset.key) {
          item.element.width = parseInt(width, 10)
          item.element.height = parseInt(height, 10)
          item.element.left = parseInt(translate[0], 10)
          item.element.top = parseInt(translate[1], 10)
        }
      })
    })
    commit()
  })
  moveableRef.on("warpEnd", (e) => {
    currentComponent.value.element.matrix3d = e.lastEvent.matrix
    addStyle(false)
    commit()
  })
  selecto.on("dragStart", (e) => {
    const moveable = moveableRef
    const { target } = e.inputEvent
    if (
      target.tagName === "BUTTON" ||
      moveable.isMoveableElement(target) ||
      targets.some((t) => t === target || t.contains(target))
    ) {
      e.stop()
    }
  })
  selecto.on("selectEnd", (e) => {
    const moveable = moveableRef
    if (e?.selected.length < 1) {
      clearComponent()
    }
    if (e?.isDragStart) {
      e.inputEvent.preventDefault()
      moveable.waitToChangeTarget().then(() => {
        moveable.dragStart(e.inputEvent)
      })
    }
    if (e?.selected?.length === 1) {
      const { key } = e.selected[0].dataset
      const component = componentList.value.find((item) => item.key === key)
      selectComponent(component)
    }
    if (e?.selected?.length > 1) {
      groupManager.value = e.selected.map((item) => {
        const { key } = item.dataset
        return componentList.value.find((v) => v.key === key)
      })
    }
    const elementGuidelines = g.subtract(componentList.value, e?.selected, function (a, b) {
      if (a.key === b.dataset.key) {
        return true
      }
    })
    moveableRef.elementGuidelines = elementGuidelines.map((v) => `.${v.key}`)
    setTargets(e.selected)
  })

  function setTargets(nextTargets) {
    targets = nextTargets
    moveableRef.target = targets
  }

  // watch(
  // 		[
  // 				() => currentComponent.value.left,
  // 				() => currentComponent.value.top,
  // 		],
  // 		([left,top]) => {
  // 			console.log(left,top)
  // 			moveableRef.request("draggable", {
  // 				x: left,
  // 				y: top,
  // 			},true);
  // 		}
  // )
  //
  // watch(
  // 		[
  // 			() => currentComponent.value.width,
  // 			() => currentComponent.value.height,
  // 		],
  // 		(value) => {
  // 			console.log(value)
  // 			moveableRef.request("resizable", {
  // 				offsetWidth: value[0],
  // 				offsetHeight: value[1],
  // 			},true);
  // 		}
  // )

  // new Guides(document.querySelector('.ruler.horizontal'), {
  //   type: 'horizontal',
  //   // displayDragPos: true,
  //   // rulerStyle: { left: '30px', width: '100%', height: '100%' },
  //   // unit: 100,
  //   // zoom: scale.value,
  //   // backgroundColor: 'transparent',
  //   // guidesOffset: 14,
  //   // textColor: isDark.value ? '#fff' : '#000'
  // }).on('changeGuides', (e) => {
  //   moveableRef.horizontalGuidelines = e.guides
  // })
  // new Guides(document.querySelector('.ruler.vertical'), {
  //   type: 'vertical',
  //   // displayDragPos: true,
  //   // rulerStyle: { top: '30px', height: '100%', width: '100%' },
  //   // unit: 100,
  //   // zoom: scale.value,
  //   // backgroundColor: 'transparent',
  //   // guidesOffset: 14,
  //   // textColor: isDark.value ? '#fff' : '#000'
  // }).on('changeGuides', (e) => {
  //   moveableRef.verticalGuidelines = e.guides
  // })
  // watch(scale, (newVal) => {
  //   guides1.zoom = newVal
  //   guides2.zoom = newVal
  // })
  // watch(isDark, (newVal) => {
  //   guides1.textColor = newVal ? '#fff' : '#000'
  //   guides2.textColor = newVal ? '#fff' : '#000'
  //   guides1.line = newVal ? '#fff' : '#000'
  //   guides2.line = newVal ? '#fff' : '#000'
  // })
})

// 给元素添加样式
/**
 * @param isBorder 是否添加border
 */
function addStyle(isBorder) {
  componentList.value.forEach((item) => {
    // 取class名
    const className = item.key
    // 获取元素
    const dom = document.querySelector(`.${className}`)
    // 给元素添加border样式
    if (isBorder) {
      dom.style.border = "1px solid #1890ff"
    } else {
      // 清除元素的border样式
      dom.style.border = ""
    }
  })
}

// 拖动组件
let handleDrag = null
const handleDragStart = (e) => {
  handleDrag = e
}
const handleDragEnd = (e) => {
  e.preventDefault()
  e.stopPropagation()
  addComponent(handleDrag, e.offsetX, e.offsetY)
}
const handleDragOver = (e) => {
  e.preventDefault()
}

// 格式刷
const { formatBrush } = useBrush()

// 组件信息
import { settings } from "@/plugins"
import PrviewComponent from "@/views/visual/screen/previewComponent.vue"
import { ref } from "vue"

const componentInfo = ref({})
// 鼠标移入展示信息
const mouseOver = async (e) => {
  componentInfo.value = {
    ...settings.value[e.name],
    ...{
      title: e.title,
      desc: e.desc
    }
  }
}
</script>

<style scoped lang="less">
.tool {
  position: relative;
  border-bottom: 1px solid var(--td-border-level-2-color);
  display: flex;
  justify-content: space-between;
  padding: 0 10px;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  height: 41px;
  align-items: center;

  &-component {
    width: 78px;
    height: 80px;
    border: 1px solid var(--color-border-1);
    // 抓手型
    cursor: pointer;
    margin: 0 6px 12px 0;
    border-radius: 4px;
    text-align: center;
    font-size: 12px;

    .t-image__wrapper {
      padding: 6px;
      height: 58px;
    }
  }
}

.canvas {
  height: calc(100% - 50px);
  position: relative;
  box-sizing: border-box;
  overflow: auto;
  background-color: var(--color-fill-2);
  @apply p-3;

  &::-webkit-scrollbar {
    width: 10px;
    height: 10px;
  }

  // 滚动条
  &-container {
    width: 100%;
    height: 100%;
    position: relative;

    .container {
      position: relative;
      width: 100%;
      height: 100%;
      transform-origin: left top;

      .component {
        position: absolute;
        &:hover {
          outline: 1px solid rgb(var(--arcoblue-4));
          pointer-events: auto;
        }
      }
    }
  }

  .ruler {
    position: absolute;
    top: 0;
    left: 0;
  }

  .ruler.horizontal {
    left: 10px;
    width: 100%;
    height: 30px;
  }

  .ruler.vertical {
    top: 10px;
    width: 30px;
    height: 100%;
  }
}
</style>
